package com.xindao.widget;

import java.util.ArrayList;
import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.TextView;

import com.xindao.R;
import com.xindao.other.ArrayUtil;

public class FanFanTextView extends TextView implements GestureDetector.OnGestureListener {

  private String[]           poemText;
  private GestureDetector    gesture;
  private Rect[]             drawArea = new Rect[8];
  private Rect[]             back     = new Rect[8];
  private float              ascent;
  private int                lastDownPos, curDownPos;
  private Drawable           slice;
  private UpdateHandler      handler;
  private int                order[]  = new int[8];
  private Random             random   = new Random();
  private ArrayList<Integer> reversed = new ArrayList<Integer>();

  private PerformOver        performOver;
  private OnOverListener     overListener;
  private static boolean     debug    = false;

  public FanFanTextView(Context context) {
    this(context, null);
  }

  public FanFanTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    handler = new UpdateHandler(this);
    slice = context.getResources().getDrawable(R.drawable.wood_slice);
    slice.setBounds(0, 0, slice.getIntrinsicWidth(), slice.getIntrinsicHeight());
    gesture = new GestureDetector(getContext(), this);
    for (int i = 0; i < drawArea.length; i++) {
      drawArea[i] = new Rect();
      back[i] = new Rect();
      order[i] = i;
    }
    lastDownPos = curDownPos = -1;
  }

  public void setPoemText(String[] text) {
    poemText = text;
    for (int i = 0; i < order.length; i++) {
      int tmp = random.nextInt(order.length);
      ArrayUtil.sweap(order, tmp, i);
      ArrayUtil.sweap(poemText, i, tmp);
    }
    requestLayout();
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    return gesture.onTouchEvent(event);
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    ascent = getPaint().getFontMetrics().ascent;
    if (null != poemText && poemText.length > 0) {
      int fW = (int) getPaint().getTextSize();
      int fL = poemText[0].length();
      FontMetrics met = getPaint().getFontMetrics();
      int fH = (int) (met.descent - met.ascent);
      int h = fH * fL;
      int l = getPaddingLeft(), t = getPaddingTop(), r = getWidth() - getPaddingRight(), b = getHeight()
          - getPaddingBottom();
      for (int i = 0; i < drawArea.length; i++) {
        drawArea[i].left = l + (r - l) * (i % 4) / 4 + ((r - l) / 4 - fW) / 2;
        drawArea[i].top = t + i / 4 * (b - t) / 2 + ((b - t) / 2 - h) / 2;
        drawArea[i].right = drawArea[i].left + fW;
        drawArea[i].bottom = drawArea[i].top + h;
        back[i].set(drawArea[i]);
        back[i].inset(-8, -8);
      }
    }
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (null != poemText && poemText.length > 0) {
      for (int i = 0; i < drawArea.length; i++) {
        Rect r = drawArea[i];
        TextPaint paint = getPaint();
        paint.setStyle(Style.STROKE);
        if (lastDownPos == i || curDownPos == i || reversed.contains(i)) {
          paint.setStyle(Style.FILL);
          drawTextVertical(canvas, r.left, r.top - ascent, poemText[i]);
        } else {
          slice.setBounds(back[i]);
          slice.draw(canvas);
          if (debug)
            canvas.drawText(String.valueOf(order[i] / 2), r.left, r.top + r.height() / 2, paint);
        }
      }
    }
  }

  private void drawTextVertical(Canvas canvas, float x, float y, String text) {
    Paint paint = getPaint();
    FontMetrics metric = paint.getFontMetrics();
    for (int i = 0; i < text.length(); i++) {
      canvas.drawText(String.valueOf(text.charAt(i)), x, y, paint);
      y += metric.descent - metric.ascent;
    }
  }

  @Override
  public boolean onDown(MotionEvent e) {
    boolean update = false;
    for (int i = 0; i < back.length; i++) {
      if (back[i].contains((int) e.getX(), (int) e.getY())) {
        if (reversed.contains(i))
          return true;
        if (lastDownPos == -1) {
          lastDownPos = i;
          update = true;
        } else if (curDownPos == -1) {
          curDownPos = i;
          if (order[lastDownPos] / 2 == order[curDownPos] / 2) {
            reversed.add(lastDownPos);
            reversed.add(curDownPos);
            lastDownPos = curDownPos = -1;
            if (reversed.size() == order.length) {
              if (null == performOver)
                performOver = new PerformOver();
              post(performOver);
            }
          }
          update = true;
        }
      }
    }
    if (update) {
      handler.clear();
      handler.update();
      invalidate();
      return true;
    }
    return false;
  }

  @Override
  public void onShowPress(MotionEvent e) {
  }

  @Override
  public boolean onSingleTapUp(MotionEvent e) {
    return false;
  }

  @Override
  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    return false;
  }

  @Override
  public void onLongPress(MotionEvent e) {

  }

  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    return false;
  }

  public void setOnOverListener(OnOverListener listener) {
    overListener = listener;
  }

  public void performOver() {
    if (null != overListener) {
      overListener.onOver();
    }
  }

  private static class UpdateHandler extends Handler {
    int                    update = 10;
    private FanFanTextView container;

    public UpdateHandler(FanFanTextView view) {
      container = view;
    }

    private void update() {
      sendEmptyMessageDelayed(update, 1000);
    }

    private void clear() {
      removeMessages(update);
    }

    @Override
    public void handleMessage(Message msg) {
      if (container.lastDownPos != -1 || container.curDownPos != -1) {
        container.lastDownPos = -1;
        container.curDownPos = -1;
        container.invalidate();
      }
    }
  }

  private class PerformOver implements Runnable {
    @Override
    public void run() {
      performOver();
    }
  }

  public interface OnOverListener {
    public void onOver();
  }
}
